/* --------------------------------------------------------- *
* __________ D E L T A S C R I P T *
* (_________() *
* / === / - A fast, dynamic scripting language *
* | == | - Version 4.13.11.0 *
* / === / - Developed by Adam R. Nelson *
* | = = | - 2011-2013 *
* / === / - Distributed under GNU LGPL v3 *
* (________() - http://github.com/ar-nelson/deltascript *
* *
* --------------------------------------------------------- */
package com.sector91.delta.script.runner;
import java.io.IOException;
import java.nio.charset.Charset;
import jline.console.ConsoleReader;
import jline.console.UserInterruptException;
import org.fusesource.jansi.Ansi.Attribute;
import org.fusesource.jansi.Ansi.Color;
import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.Ansi;
import com.sector91.delta.script.DScriptContext;
import com.sector91.delta.script.DScriptErr;
import com.sector91.delta.script.DeltaScript;
import com.sector91.delta.script.instrs.DSInstr;
import com.sector91.delta.script.objects.DS_Blank;
import com.sector91.delta.script.objects.DS_Boolean;
import com.sector91.delta.script.objects.DS_Object;
import com.sector91.delta.script.objects.DS_Scope;
import com.sector91.delta.script.objects.DS_String;
import com.sector91.delta.script.parser.DScriptLexer;
import com.sector91.delta.script.parser.DScriptLexerException;
import com.sector91.delta.script.parser.DScriptParser;
import com.sector91.delta.script.parser.DScriptParserException;
import com.sector91.delta.script.parser.LexToken;
public class DeltaScriptFancyInterpreter implements Runnable
{
private static final String
UNICODE_PROMPT = " \u03b4 > ",
ASCII_PROMPT = " ds> ",
BLOCK_PROMPT = "...> ",
RESULT_PROMPT = "out) ",
ERROR_PROMPT = "err! ",
SCRIPT_NAME = "[Interpreter Script]";
private final boolean unicode;
private boolean running;
private String line = null;
private final ConsoleReader reader;
private final DScriptContext context;
private final DS_Scope scope;
public DeltaScriptFancyInterpreter(DScriptContext context, DS_Scope scope)
throws IOException
{
this.reader = new ConsoleReader();
this.reader.setExpandEvents(false);
this.reader.setBellEnabled(false);
this.reader.setHandleUserInterrupt(true);
this.context = context;
this.scope = scope;
this.unicode = Charset.defaultCharset().contains(
Charset.forName("UTF-8"));
}
public static void main(String[] args) throws IOException
{
final DScriptContext context = new DScriptContext();
new DeltaScriptFancyInterpreter(context, context.createScope()).run();
}
public synchronized void run()
{
running = true;
try
{
AnsiConsole.systemInstall();
writeBanner();
while (running)
{
try
{
final DSInstr instr = readInput();
if (instr != null)
{
final DS_Object result = DeltaScript.exec(instr, scope,
context);
writeResult(result);
}
}
catch (DScriptParserException ex)
{writeParseError(line, ex);}
catch (DScriptErr err)
{writeDeltaScriptError(line, err);}
catch (UserInterruptException ex)
{
AnsiConsole.out.println("Goodbye!");
System.exit(0);
}
catch (Exception ex)
{writeJavaError(ex);}
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
private void writeBanner() throws IOException
{
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.CYAN).a(" __________ ").fg(Color.DEFAULT).a(Attribute.INTENSITY_BOLD)
.a(" D E L T A S C R I P T").reset().newline()
.fg(Color.CYAN).a(" (_________()").newline()
.fg(Color.CYAN).a(" / === / ").reset().a(" - Version ").a(DeltaScript.VERSION).newline()
.fg(Color.CYAN).a(" | == | ").reset().a(" - Developed by ").a(DeltaScript.AUTHOR).newline()
.fg(Color.CYAN).a(" / === / ").reset().a(" - ").a(DeltaScript.WEBSITE).newline()
.fg(Color.CYAN).a(" | = = | ").reset() .a(" - Distributed under the GNU LGPL v3").newline()
.fg(Color.CYAN).a(" / === / ").newline()
.fg(Color.CYAN).a(" (________() ").fg(Color.RED).a("Press CTRL-C to exit.")
.reset().newline());
}
private DSInstr readInput() throws IOException, DScriptParserException
{
line = reader.readLine(Ansi.ansi()
.fg(Color.YELLOW).a(unicode? UNICODE_PROMPT:ASCII_PROMPT).reset()
.toString());
final DScriptParser parser = new DScriptParser(context);
DScriptLexer lexer = new DScriptLexer(line);
LexToken token = null;
while (lexer.hasNext())
token = lexer.next();
if (token == null) return null;
try
{
token.value();
while (lexer.topUnclosedToken() != null)
{
line += "\n" + reader.readLine(Ansi.ansi()
.fg(Color.GREEN).a(BLOCK_PROMPT).reset()
.toString());
lexer = new DScriptLexer(line);
token = null;
while (lexer.hasNext())
token = lexer.next();
if (token != null) token.value();
}
return parser.compile(line, SCRIPT_NAME);
}
catch (DScriptLexerException ex)
{
// Compile so that a parser exception will be thrown.
parser.compile(line, SCRIPT_NAME);
}
return null;
}
private void writeResult(DS_Object result) throws IOException
{
Color color = Color.CYAN;
String str = String.valueOf(result);
if (result instanceof DS_String)
{
color = Color.GREEN;
str = "\"" + str.replace("\\","\\\\").replace("\"","\\\"") + "\"";
}
else if (result instanceof DS_Boolean || result == DS_Blank.BLANK)
color = Color.MAGENTA;
// TODO: Special formatting for arrays, lists, maps...
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.BLUE).a(RESULT_PROMPT).fg(color).a(str).reset());
}
private void writeParseError(String source, DScriptParserException error)
{
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).a("== Parse Error ==").reset());
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).reset().a(error.getMessage()));
for (String line : error.getLocatorText(source).split("\r?\n"))
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).reset().a(line));
}
private void writeDeltaScriptError(String source, DScriptErr error)
{
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).a("== DeltaScript Error ==").reset());
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).reset().a(error.getMessage()));
for (String line : error.getLocatorText(SCRIPT_NAME, source).split("\r?\n"))
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).reset().a(line));
}
private void writeJavaError(Throwable error)
{
AnsiConsole.out.println(Ansi.ansi()
.fg(Color.RED).a(ERROR_PROMPT).a("== Java Error ==").reset());
error.printStackTrace(AnsiConsole.out);
}
}